package top.atcra.rpc.utils;

import lombok.extern.slf4j.Slf4j;
import top.atcra.rpc.exception.NetworkException;

import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

@Slf4j
public class IPAddrUtil {
    /**
     * 获取本机的所有IPv4地址
     *
     * @return 本机的所有IPv4地址
     */
    public static List<String> getAllLocalIpv4() {
        List<String> list = new ArrayList<>();
        try {
            // 获取所有的网卡信息
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface interface_ = interfaces.nextElement();
                // 过滤非回环接口和虚拟接口
                if (interface_.isLoopback() || interface_.isVirtual() || !interface_.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = interface_.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    // 过滤IPv6地址/回环地址/本地链路以太网地址
                    if (addr instanceof Inet6Address || addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
                        continue;
                    }
                    String ipAddress = addr.getHostAddress();
//                    if(log.isDebugEnabled()){
//                        log.debug("Local ipv4 address: {}",ipAddress);
//                    }
                    list.add(ipAddress);
                }
            }

            return list;
        } catch (SocketException e) {
            log.error("can't detect local ipv4 address. reason: ", e);
            throw new NetworkException(e);
        }
    }


    /**
     * 获取在指定子网中的本机IPv4地址
     *
     * @param subnetPrefix 子网前缀
     * @return 在指定子网中的本机IPv4地址
     */
    public static String getLocalIpv4InSubnet(String subnetPrefix) {
        for (String ip : getAllLocalIpv4()) {
            if (ip.startsWith(subnetPrefix)) {
                return ip;
            }
        }
        return null;
    }

    /**
     * 尝试获取一个未被占用的端口
     *
     * @return 未被占用的端口
     * @throws NetworkException 网络异常
     */
    public static int getAvailablePort() {
        try (ServerSocket serverSocket = new ServerSocket(0)) { // 0 表示由系统自动分配空闲端口
            return serverSocket.getLocalPort();
        } catch (Exception e) {
            log.error("can't get available port. reason: ", e);
            throw new NetworkException(e);
        }
    }
}
